# -*- encoding:utf-8 -*-
# @Date  :2018-10-21
# @Author:张璐萍（zhangluping@antiy.cn）

# 运行监控
import json
from flask import Blueprint, g
from psycopg2 import connect
from psycopg2.extras import RealDictCursor
from lib.validform import V, ValidateForm
from lib import auth, record
from config import config
app = Blueprint(__name__ + "_app", __name__)


@app.before_request
def setupdb():
    g.conn = connect(**config.DatabaseConfig.siem)
    g.cursor = g.conn.cursor(cursor_factory=RealDictCursor)


@app.teardown_request
def unsetdb(exception):
    if g.cursor:
        g.cursor.close()
        g.cursor = None
    if g.conn:
        g.conn.close()
        g.conn = None


# 添加要监测的服务
@app.route('/api/operation/update', methods=['POST'])
@auth.permission("operation", "readOnly")
def updateServices(_currUser):
    try:
        form = ValidateForm(
            # 实际上每次只添加一个服务
            id=['服务id', V.required()],
            service_name=['服务名称', V.required()]
        )
        (flag, data) = form.validate()
        if not flag:
            data['status'] = 'fail'
            return json.dumps(data)
        data['id'] = json.loads(data['id'])
        g.cursor.execute("""update h_service_info set is_use= '1' where service_id='%s'""" % (data["id"]))
        g.conn.commit()
        rem = {
            "服务id": data['id'],
            "服务名称": data['service_name']
        }
        auth.logsync(
            _currUser, {
                "function": "运行监控",
                "type": "新增",
                "remark": "添加要监测的服务:" + record.recodelog(rem)
            })
        return json.dumps({
            "status": "success",
            "msg": '添加成功'
        })
    except Exception, e:
            return json.dumps({"status": "except", 'msg': '添加失败', 'warn': str(e)})


# 删除监测的服务
@app.route('/api/operation/delete', methods=['POST'])
@auth.permission("operation", "readOnly")
def deleteService(_currUser):
    try:
        form = ValidateForm(
            service_id=['服务id', V.required()],
            service_name=['服务名称', V.required()]
        )
        (flag, data) = form.validate()
        if not flag:
            data['status'] = 'fail'
            return json.dumps(data)
        g.cursor.execute("""update h_service_info set is_use= '0' where service_id='%s'""" % (data['service_id']))
        g.conn.commit()
        rem = {
            "服务id": data['service_id'],
            "服务名称": data['service_name']
        }
        auth.logsync(
            _currUser, {
                "function": "运行监控",
                "type": "删除",
                "remark": "删除监测的服务:" + record.recodelog(rem)
            })
        return json.dumps({
            "status": "success",
            "msg": '删除服务成功'
        })
    except Exception, e:
            return json.dumps({"status": "except", 'msg': '删除服务失败', 'warn': str(e)})


# 查询所有服务名称
@app.route('/api/operation/get', methods=['GET'])
@auth.permission("operation", "readOnly")
def getServices(_currUser):
    try:
        g.cursor.execute("""select distinct service_id,service_name, is_use from h_service_info""")
        return json.dumps({
            "status": "success",
            "data": g.cursor.fetchall(),
            "msg": '查询服务名称成功'
        })
    except Exception, e:
            return json.dumps({"status": "except", 'msg': '查询服务名称成功', 'warn': str(e)})


# 更改时间 查询某服务的服务运行环境情况
@app.route('/api/operation/status', methods=['POST'])
@auth.permission("operation", "readOnly")
def delete(_currUser):
    try:
        form = ValidateForm(
            interval=['时间段', V.required()],
            service_id=['服务id', V.required()]
        )
        (flag, data) = form.validate()
        if not flag:
            data['status'] = 'fail'
            return json.dumps(data)
            
        log = 'h_service_ip_log'
        if data["interval"] == '12 hour' or data["interval"] == '24 hour':
            log = log + '_hour'
        elif data["interval"] == '7 day' or data["interval"] == '30 day':
            log = log + '_day'
        else:
            pass

        sql = """with h_device_log as (
                    select b.service_id,
                        a.host_name,
                        b.ip_addr,
                        log_time,
                        r_time,
                        disk_read,
                        disk_write,
                        disk_used,
                        disk_space,
                        memory_used,
                        memory_space,
                        cpu_pre,
                        round((memory_used::numeric/memory_space::numeric)*100,1) as memory_pre,
                        round((disk_used::numeric/disk_space::numeric)*100, 1) as disk_pre,
                        round((disk_read),1) as read,
                        round((disk_write),1) as write,
                        row_number()over(partition by service_id, a.host_name order by log_time desc) as rn
                        from %s a,h_service_ip_list b
                        where a.host_name = b.host_name and log_time >= now() - "interval" '%s' and service_id = '%s'
                        order by service_id,host_name,log_time
                )
                select * from (
                    select service_id,
                        d.host_name,
                        max(d.ip_addr) as ip_addr,
                        array_agg(d2t(d.log_time)) as log_time,
                        array_agg(d.cpu_pre::float) as cpu_pre, 
                        array_agg(d.memory_pre::float) as memory_pre,
                        array_agg(d.disk_pre::float) as disk_pre, 
                        array_agg(d.read::float) as read, 
                        array_agg(d.write::float) as write
                    from h_device_log d
                    group by d.service_id, d.host_name
                    ) a
                left join  (
                    select max(e.service_id) as service_id,
                        max(e.host_name) as host_name,
                        sum(case when e.cpu_pre >= 90 or e.memory_pre >= 80 or e.disk_pre >= 90 then 1 else 0 end) as status,
                        max(e.disk_used) disk_used, 
                        max(e.disk_space)as disk_space, 
                        max(e.cpu_pre) as cpu,
                        max(e.memory_used)as memory_used, 
                        max(e.memory_space)as memory_space,  
                        max(e.disk_write)as disk_write,
                        max(e.disk_read)as disk_read
                        from h_device_log e where e.rn='1' group by e.host_name
                    ) b
                on a.host_name = b.host_name""" % (log, data['interval'], data['service_id'])
        print sql
        g.cursor.execute(sql)
        devices = g.cursor.fetchall()
        count = 0
        if devices:
            for item in devices:
                if item['status'] > 0:
                    count += 1
                else:
                    pass
        if count > 0:
            deviceStatus = '异常'
        else:
            deviceStatus = '正常'
        return json.dumps({
            "status": "success",
            "msg": '查询成功',
            "deviceStatus": deviceStatus,
            "devices": devices,
            "id": data['service_id']
        })
    except Exception, e:
            return json.dumps({"status": "except", 'msg': '查询服务运行环境失败', 'warn': str(e)})


# 服务运行状态统计 和 服务最新5次状态
@app.route('/api/operation/information', methods=["POST"])
@auth.permission("operation", "readOnly")
def statistics(_currUser):
    try:
        # 存储统计信息
        statistics = {}
        g.cursor.execute("""select d.servicetotal, d.monitor, b.devicetotal
                            from (
                                select count(distinct a.host_name) as devicetotal
                                from h_service_ip_list a
                                where a.service_id in (select distinct service_id from h_service_info where is_use = '1')
                                ) b,
                                (
                                select count(c.service_id) as servicetotal,
                                    sum(case when c.is_use='1' then 1 else 0 end) as monitor
                                 from (select distinct a.service_id, a.is_use from h_service_info a) c
                                ) d""")
        statistics = g.cursor.fetchall()[0]
        statistics['normal'] = 0
        statistics['abnormal'] = []
        g.cursor.execute("""select distinct service_name, service_id from h_service_info where is_use = '1' order by service_id""")
        services = g.cursor.fetchall()
        # 存储服务状态信息
        data = []
        if services:
            for item in services:
                service = {}
                service['name'] = item['service_name']
                service['id'] = item['service_id']
                # 统计设备状态
                count = 0
                # 查询服务的最近5次状态日志
                g.cursor.execute("""select * from (
                                        select max(a.service_id) as service_id,
                                            d2t(a.log_time) as log_time,
                                            max(case a.status when 'FATAL' then 3 when 'STOPPED' then 2 when 'RUNNING' then 1 end) as status
                                        from h_service_log a
                                        where a.service_id='%s'
                                        group by a.log_time
                                        order by a.log_time desc
                                        offset 0 limit 5
                                        ) b,
                                        (
                                        select distinct(c.service_name)
                                            from h_service_info c where c.service_id = '%s'
                                        ) d""" % (item['service_id'], item['service_id']))
                service['log'] = g.cursor.fetchall()
                data.append(service)
                g.cursor.execute("""with h_device_log as (
                                        select b.service_id,
                                            a.host_name,
                                            b.ip_addr,
                                            log_time,
                                            r_time,
                                            disk_read,
                                            disk_write,
                                            disk_used,
                                            disk_space,
                                            memory_used,
                                            memory_space,
                                            cpu_pre,
                                            round((memory_used::numeric/memory_space::numeric)*100,1) as memory_pre,
                                            round((disk_used::numeric/disk_space::numeric)*100, 1) as disk_pre,
                                            round((disk_read),1) as read,
                                            round((disk_write),1) as write,
                                            row_number()over(partition by service_id, a.host_name order by log_time desc) as rn
                                            from h_service_ip_log_hour a,h_service_ip_list b
                                            where a.host_name = b.host_name and log_time >= now() - "interval" '12 hour' and service_id = '%s'
                                            order by service_id,host_name,log_time
                                    )
                                    select * from (
                                        select service_id,
                                            d.host_name,
                                            max(d.ip_addr) as ip_addr,
                                            array_agg(d2t(d.log_time)) as log_time,
                                            array_agg(d.cpu_pre::float) as cpu_pre,
                                            array_agg(d.memory_pre::float) as memory_pre,
                                            array_agg(d.disk_pre::float) as disk_pre,
                                            array_agg(d.read::float) as read,
                                            array_agg(d.write::float) as write
                                        from h_device_log d
                                        group by d.service_id, d.host_name
                                        ) a
                                    left join  (
                                        select max(e.service_id) as service_id,
                                            max(e.host_name) as host_name,
                                            sum(case when e.cpu_pre >= 90 or e.memory_pre >= 80 or e.disk_pre >= 90 then 1 else 0 end) as status,
                                            max(e.disk_used) disk_used,
                                            max(e.disk_space)as disk_space,
                                            max(e.cpu_pre) as cpu,
                                            max(e.memory_used)as memory_used,
                                            max(e.memory_space)as memory_space,
                                            max(e.disk_write)as disk_write,
                                            max(e.disk_read)as disk_read
                                            from h_device_log e where e.rn='1' group by e.host_name
                                        ) b
                                    on a.host_name = b.host_name""" % (item['service_id']))
                service['devices'] = g.cursor.fetchall()
                if service['devices']:
                    for device in service['devices']:
                        if device['status'] > 0:
                            count += 1
                        else:
                            pass
                if service['log']:
                    if service['log'][0]['status'] == 3:
                        statistics['abnormal'].append(service['log'][0]['service_name'])
                    elif service['log'][0]['status'] == 1:
                        statistics['normal'] += 1
                    else:
                        pass
                if count > 0:
                    service['deviceStatus'] = '异常'
                else:
                    service['deviceStatus'] = '正常'

        return json.dumps({"status": "success", "statistics": statistics, "data": data}, ensure_ascii=False)
    except Exception, e:
        return json.dumps({"status": "except", "msg": "查询数据失败", "warn": str(e)})
